package billing

import (
	"fmt"
	"log"
	"sync"
	"time"
)

// ========================================
// 带宽限制拦截器 (Bandwidth Limit Interceptor)
// 用于控制用户的带宽使用，超出限制后拦截请求
// 使用令牌桶算法(Token Bucket)实现平滑限流
// ========================================

// BandwidthPlan 带宽套餐
type BandwidthPlan struct {
	UserID         string      // 用户ID
	MaxBandwidth   int64       // 最大带宽（字节/秒）
	CurrentUsage   int64       // 当前使用带宽（字节/秒）
	BurstSize      int64       // 突发大小（字节）
	Tokens         float64     // 当前令牌数
	LastRefillTime time.Time   // 上次令牌补充时间
	PaymentType    PaymentType // 付费类型
	PaymentURL     string      // 付费URL
	OrderID        string      // 订单号
	mu             sync.Mutex  // 令牌桶锁
}

// BandwidthStorage 带宽套餐存储接口
type BandwidthStorage interface {
	// GetPlan 获取用户的带宽套餐
	GetPlan(userID string) (*BandwidthPlan, error)

	// TryConsume 尝试消费令牌（带宽）
	// 返回：是否成功, 当前可用令牌, 错误
	TryConsume(userID string, bytes int64) (bool, float64, error)
}

// InMemoryBandwidthStorage 内存存储实现
type InMemoryBandwidthStorage struct {
	plans map[string]*BandwidthPlan
	mu    sync.RWMutex
}

// NewInMemoryBandwidthStorage 创建内存存储
func NewInMemoryBandwidthStorage() *InMemoryBandwidthStorage {
	return &InMemoryBandwidthStorage{
		plans: make(map[string]*BandwidthPlan),
	}
}

// SetPlan 设置用户带宽套餐（仅用于测试/演示）
func (s *InMemoryBandwidthStorage) SetPlan(userID string, maxBandwidthMBps int64, paymentType PaymentType, paymentURL, orderID string) {
	s.mu.Lock()
	defer s.mu.Unlock()

	maxBandwidth := maxBandwidthMBps * 1024 * 1024 // 转换为字节/秒
	burstSize := maxBandwidth * 2                  // 突发大小为最大带宽的2倍

	s.plans[userID] = &BandwidthPlan{
		UserID:         userID,
		MaxBandwidth:   maxBandwidth,
		CurrentUsage:   0,
		BurstSize:      burstSize,
		Tokens:         float64(burstSize), // 初始令牌为突发大小
		LastRefillTime: time.Now(),
		PaymentType:    paymentType,
		PaymentURL:     paymentURL,
		OrderID:        orderID,
	}
}

// GetPlan 获取套餐
func (s *InMemoryBandwidthStorage) GetPlan(userID string) (*BandwidthPlan, error) {
	s.mu.RLock()
	plan, exists := s.plans[userID]
	s.mu.RUnlock()

	if !exists {
		// 🚀 默认策略：新用户给予100Mbps带宽
		s.mu.Lock()
		maxBandwidth := int64(100 * 1024 * 1024) // 100MB/s
		burstSize := maxBandwidth * 2

		plan = &BandwidthPlan{
			UserID:         userID,
			MaxBandwidth:   maxBandwidth,
			CurrentUsage:   0,
			BurstSize:      burstSize,
			Tokens:         float64(burstSize),
			LastRefillTime: time.Now(),
			PaymentType:    PaymentTypeCashier,
			PaymentURL:     fmt.Sprintf("https://pay.example.com/bandwidth?user=%s", userID),
			OrderID:        fmt.Sprintf("BW-ORDER-%s-%d", userID, time.Now().Unix()),
		}
		s.plans[userID] = plan
		s.mu.Unlock()
	}

	return plan, nil
}

// TryConsume 尝试消费令牌（带宽）
func (s *InMemoryBandwidthStorage) TryConsume(userID string, bytes int64) (bool, float64, error) {
	plan, err := s.GetPlan(userID)
	if err != nil {
		return false, 0, err
	}

	plan.mu.Lock()
	defer plan.mu.Unlock()

	// 🚀 令牌桶算法：计算应该补充的令牌
	now := time.Now()
	elapsed := now.Sub(plan.LastRefillTime).Seconds()

	// 根据最大带宽补充令牌（每秒补充 MaxBandwidth 个令牌）
	tokensToAdd := elapsed * float64(plan.MaxBandwidth)
	plan.Tokens += tokensToAdd
	plan.LastRefillTime = now

	// 令牌数不能超过突发大小
	if plan.Tokens > float64(plan.BurstSize) {
		plan.Tokens = float64(plan.BurstSize)
	}

	// 尝试消费令牌
	if plan.Tokens >= float64(bytes) {
		plan.Tokens -= float64(bytes)
		plan.CurrentUsage = int64(float64(plan.MaxBandwidth) - plan.Tokens/elapsed)
		return true, plan.Tokens, nil
	}

	// 令牌不足
	return false, plan.Tokens, nil
}

// BandwidthLimitInterceptor 带宽限制拦截器
type BandwidthLimitInterceptor struct {
	storage BandwidthStorage
	enabled bool
}

// NewBandwidthLimitInterceptor 创建带宽限制拦截器
func NewBandwidthLimitInterceptor(storage BandwidthStorage) *BandwidthLimitInterceptor {
	if storage == nil {
		storage = NewInMemoryBandwidthStorage()
	}

	return &BandwidthLimitInterceptor{
		storage: storage,
		enabled: true,
	}
}

// Name 拦截器名称
func (i *BandwidthLimitInterceptor) Name() string {
	return "BandwidthLimitInterceptor"
}

// Priority 优先级（20 = 中优先级，在流量配额之后检查）
func (i *BandwidthLimitInterceptor) Priority() int {
	return 20
}

// Enable 启用拦截器
func (i *BandwidthLimitInterceptor) Enable() {
	i.enabled = true
	log.Printf("💰 [计费] 带宽限制拦截器已启用")
}

// Disable 禁用拦截器
func (i *BandwidthLimitInterceptor) Disable() {
	i.enabled = false
	log.Printf("💰 [计费] 带宽限制拦截器已禁用")
}

// Intercept 拦截逻辑
func (i *BandwidthLimitInterceptor) Intercept(ctx *InterceptContext) (*InterceptResult, error) {
	// 如果禁用，直接放行
	if !i.enabled {
		return nil, nil
	}

	// 计算本次请求的数据量（请求 + 预估响应）
	// 注意：这里只能估算请求大小，响应大小在请求完成后才知道
	estimatedBytes := ctx.RequestSize
	if estimatedBytes <= 0 {
		estimatedBytes = 1024 // 至少1KB
	}

	// 尝试消费带宽
	success, availableTokens, err := i.storage.TryConsume(ctx.UserID, estimatedBytes)
	if err != nil {
		return nil, fmt.Errorf("检查带宽限制失败: %v", err)
	}

	if !success {
		// 带宽不足，获取套餐信息
		plan, _ := i.storage.GetPlan(ctx.UserID)
		if plan == nil {
			return &InterceptResult{
				Available:   false,
				Reason:      "带宽限制超出（无法获取套餐信息）",
				PaymentType: PaymentTypeCashier,
				PaymentURL:  "https://pay.example.com/bandwidth",
				OrderID:     fmt.Sprintf("BW-ORDER-%d", time.Now().Unix()),
			}, nil
		}

		log.Printf("🚫 [计费] 带宽限制超出: UserID=%s, MaxBandwidth=%.2fMB/s, AvailableTokens=%.2fKB",
			ctx.UserID, float64(plan.MaxBandwidth)/(1024*1024), availableTokens/1024)

		return &InterceptResult{
			Available:   false,
			Reason:      fmt.Sprintf("带宽限制超出 (最大带宽: %.2f MB/s)", float64(plan.MaxBandwidth)/(1024*1024)),
			PaymentType: plan.PaymentType,
			PaymentURL:  plan.PaymentURL,
			OrderID:     plan.OrderID,
			Extra: map[string]interface{}{
				"max_bandwidth_bps":  plan.MaxBandwidth,
				"max_bandwidth_mbps": float64(plan.MaxBandwidth) / (1024 * 1024),
				"available_tokens":   availableTokens,
				"burst_size":         plan.BurstSize,
			},
		}, nil
	}

	// 带宽充足，放行
	return nil, nil
}

// GetStorage 获取存储实例（用于外部设置套餐）
func (i *BandwidthLimitInterceptor) GetStorage() BandwidthStorage {
	return i.storage
}
